/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package GlobalObservingSystem.Mundo.Predicciones;

import GlobalObservingSystem.Interfaces.IOraculo;
import GlobalObservingSystem.Mundo.BaseDatos.AdministradorBD;
import GlobalObservingSystem.Mundo.BaseDatos.MedidaBD;
import GlobalObservingSystem.Mundo.BaseDatos.MedidasConsultaBD;
import GlobalObservingSystem.Mundo.Coordenada;


import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author js.rojas131
 */
public class Oraculo implements IOraculo {

    private MedidasConsultaBD[] datosM;
    private double[][] yTranspose;
    private double[][] dMatrix;
    private double[][] predictorValues;
    private int maxJ;
    private int maxK;
    private double maxAbsoluteValue;
    private double sinT;
    private double cosT;

    /**
     * Predice el clima para una zona alrededor de un punto terrestre
     * @param tipoMedida el tipo de medidas tomadas en cuenta para predecir
     * @param latitud primera coordenada del punto
     * @param longitud segunda coordenada del punto
     * @param perimetro perimetro de alcance alrededor del punto
     * @param fecha fecha en que se toman los datos para la predicción
     * @return Cadena con la información de la predicción
     */
    public String predecirClima(Coordenada latitud, Coordenada longitud, short perimetro, Date fecha) {
        Coordenada lat1 = new Coordenada(latitud.getFlotante()-perimetro );
        Coordenada lat2 = new Coordenada(latitud.getFlotante()+perimetro );

        Coordenada lon1 = new Coordenada(longitud.getFlotante()-perimetro );
        Coordenada lon2 = new Coordenada(longitud.getFlotante()+perimetro );

        return predecirClima(lat1, lon1, lat2, lon2, fecha);
    }

    /**
     * Predice el clima para una zona delimitada por dos puntos terrestres
     * @param tipoMedida el tipo de medidas tomadas en cuenta para predecir
     * @param latitud1 primera coordenada del primer punto
     * @param longitud1 segunda coordenada del primer punto
     * @param latitud2 primera coordenada del segundo punto
     * @param longitud2 segunda coordenada del segundo punto
     * @param tiempo fecha en que se toman los datos para la predicción
     * @return Cadena con la información de la predicción
     */
    public String predecirClima(Coordenada latitud1, Coordenada longitud1, Coordenada latitud2, Coordenada longitud2, Date tiempo) {
        double latmin = Math.min(latitud1.getFlotante(), latitud2.getFlotante());
        double latmax = Math.max(latitud1.getFlotante(), latitud2.getFlotante());
        double lonmin = Math.min(longitud1.getFlotante(), longitud2.getFlotante());
        double lonmax = Math.max(longitud1.getFlotante(), longitud2.getFlotante());

        ArrayList<MedidaBD> a;
        try
        {
            a =  AdministradorBD.getInstance().darMedidaZonasFechas(latmin, lonmin, tiempo, latmax, lonmax, tiempo);
        }
        catch( Exception e )
        {
            a = new ArrayList<MedidaBD>();
        }

        if( a == null )
            return "8.png";

        ArrayList<MedidaBD> a1 = new ArrayList<MedidaBD>();
        ArrayList<MedidaBD> a2 = new ArrayList<MedidaBD>();
        ArrayList<MedidaBD> a3 = new ArrayList<MedidaBD>();
        ArrayList<MedidaBD> a4 = new ArrayList<MedidaBD>();
        ArrayList<MedidaBD> a5 = new ArrayList<MedidaBD>();
        ArrayList<MedidaBD> a6 = new ArrayList<MedidaBD>();
        ArrayList<MedidaBD> a7 = new ArrayList<MedidaBD>();

        int i = 0;
        for( ; i < a.size(); i++ )
        {
            MedidaBD m = a.get(i);
            if( m.getTipoMedicion() == 1 )
                a1.add(m);
            else if( m.getTipoMedicion() == 2 )
                a2.add(m);
            else if( m.getTipoMedicion() == 3 )
                a3.add(m);
            else if( m.getTipoMedicion() == 4 )
                a4.add(m);
            else if( m.getTipoMedicion() == 5 )
                a5.add(m);
            else if( m.getTipoMedicion() == 6 )
                a6.add(m);
            else if( m.getTipoMedicion() == 7 )
                a7.add(m);
        }

        double k;

        i = 0;
        k = 0;
        for( ; i < a1.size(); i++ )
        {
            k += a1.get(i).getValor();
        }
        if( i > 0 )
        {
            k = k/i;
        }
        else
            k = 0;

        double presion = k;

        i = 0;
        k = 0;
        for( ; i < a2.size(); i++ )
        {
            k += a2.get(i).getValor();
        }
        if( i > 0 )
        {
            k = k/i;
        }
        else
            k = 0;

        double viento = k;

        i = 0;
        k = 0;
        for( ; i < a3.size(); i++ )
        {
            k += a3.get(i).getValor();
        }
        if( i > 0 )
        {
            k = k/i;
        }
        else
            k = 0;

        double dirViento = k;

        i = 0;
        k = 0;
        for( ; i < a4.size(); i++ )
        {
            k += a4.get(i).getValor();
        }
        if( i > 0 )
        {
            k = k/i;
        }
        else
            k = 0;

        double temp = k;

        i = 0;
        k = 0;
        for( ; i < a5.size(); i++ )
        {
            k += a5.get(i).getValor();
        }
        if( i > 0 )
        {
            k = k/i;
        }
        else
            k = 0;

        double humedad = k;

        i = 0;
        k = 0;
        for( ; i < a6.size(); i++ )
        {
            k += a6.get(i).getValor();
        }
        if( i > 0 )
        {
            k = k/i;
        }
        else
            k = 0;

        double agua = k;

        i = 0;
        k = 0;
        for( ; i < a1.size(); i++ )
        {
            k += a1.get(i).getValor();
        }
        if( i > 0 )
        {
            k = k/i;
        }
        else
            k = 0;

        double lluvia = k;

        if( tiempo.getDate() == 12 && tiempo.getMonth() == 12 && tiempo.getYear() == 2012 )
            return "0.png";

        if( viento >= 119000 && presion >= 92000 )
            return "1.png";

        if( humedad >= 100 && viento >= 8000 && viento <= 32000 && lluvia >= 2 && lluvia <= 15 )
            return "2.png";

        if( humedad >= 100 && viento >= 8000 && viento <= 32000 && lluvia >= 15 )
            return "3.png";

        if( humedad >= 90 && humedad <= 100 && temp >= 270 && temp <= 277 )
            return "4.png";

        if( lluvia == 0 )
            return "5.png";

        if( humedad >= 80 && humedad <= 90 )
            return "6.png";

        if( temp <= 290 && viento >= 7000 && humedad >= 50 && lluvia >= 70 )
            return "7.png";

        if( lluvia <= 30 )
            return "8.png";

        if( lluvia >= 10 && temp >= 300 )
            return "9.png";

        if( viento >= 63000 && humedad >= 50 && lluvia >= 10 )
            return "a.png";

        if( humedad >= 90 && temp >= 300 )
            return "b.png";

        if( viento >= 119000 )
            return "c.png";

        return "8.png";
    }

    /**
     * Genera un reporte de datos entre ciertas fechas y ciertos puntos terrestres
     *  @param latitud1 primera coordenada del primer punto
     * @param longitud1 segunda coordenada del primer punto
     * @param latitud2 primera coordenada del segundo punto
     * @param longitud2 segunda coordenada del segundo punto
     * @param inicio fecha de inicio del reporte
     * @param fin fecha de fin del reporte
     * @return Cadena con la información del reporte
     */
    public String generarReporte(Coordenada latitud1, Coordenada longitud1, Coordenada latitud2, Coordenada longitud2, Date inicio, Date fin) {
        double latmin = Math.min(latitud1.getFlotante(), latitud2.getFlotante());
        double latmax = Math.max(latitud1.getFlotante(), latitud2.getFlotante());
        double lonmin = Math.min(longitud1.getFlotante(), longitud2.getFlotante());
        double lonmax = Math.max(longitud1.getFlotante(), longitud2.getFlotante());
        Date min;
        Date max;
        if( fin.after(inicio) )
        {
            min = inicio;
            max = fin;
        }
        else
        {
            min = fin;
            max = inicio;
        }

        try
        {
            ArrayList<MedidaBD> a =  AdministradorBD.getInstance().darMedidaZonasFechas(latmin, lonmin, min, latmax, lonmax, max);

            if( a == null )
                return "Sin datos:Sin datos:Sin datos:Sin datos:Sin datos:Sin datos:Sin datos";

            ArrayList<MedidaBD> a1 = new ArrayList<MedidaBD>();
            ArrayList<MedidaBD> a2 = new ArrayList<MedidaBD>();
            ArrayList<MedidaBD> a3 = new ArrayList<MedidaBD>();
            ArrayList<MedidaBD> a4 = new ArrayList<MedidaBD>();
            ArrayList<MedidaBD> a5 = new ArrayList<MedidaBD>();
            ArrayList<MedidaBD> a6 = new ArrayList<MedidaBD>();
            ArrayList<MedidaBD> a7 = new ArrayList<MedidaBD>();

            int i = 0;
            for( ; i < a.size(); i++ )
            {
                MedidaBD m = a.get(i);
                if( m.getTipoMedicion() == 1 )
                    a1.add(m);
                else if( m.getTipoMedicion() == 2 )
                    a2.add(m);
                else if( m.getTipoMedicion() == 3 )
                    a3.add(m);
                else if( m.getTipoMedicion() == 4 )
                    a4.add(m);
                else if( m.getTipoMedicion() == 5 )
                    a5.add(m);
                else if( m.getTipoMedicion() == 6 )
                    a6.add(m);
                else if( m.getTipoMedicion() == 7 )
                    a7.add(m);
            }

            String res = "";
            double k;

            i = 0;
            k = 0;
            for( ; i < a1.size(); i++ )
            {
                k += a1.get(i).getValor();
            }
            if( i > 0 )
            {
                k = k/i;
                res += k +":";
            }
            else
                res += "Sin datos:";

            i = 0;
            k = 0;
            for( ; i < a2.size(); i++ )
            {
                k += a2.get(i).getValor();
            }
            if( i > 0 )
            {
                k = k/i;
                res += k +":";
            }
            else
                res += "Sin datos:";

            i = 0;
            k = 0;
            for( ; i < a3.size(); i++ )
            {
                k += a3.get(i).getValor();
            }
            if( i > 0 )
            {
                k = k/i;
                res += k +":";
            }
            else
                res += "Sin datos:";

            i = 0;
            k = 0;
            for( ; i < a4.size(); i++ )
            {
                k += a4.get(i).getValor();
            }
            if( i > 0 )
            {
                k = k/i;
                res += k +":";
            }
            else
                res += "Sin datos:";
            
            i = 0;
            k = 0;
            for( ; i < a5.size(); i++ )
            {
                k += a5.get(i).getValor();
            }
            if( i > 0 )
            {
                k = k/i;
                res += k +":";
            }
            else
                res += "Sin datos:";
            
            i = 0;
            k = 0;
            for( ; i < a6.size(); i++ )
            {
                k += a6.get(i).getValor();
            }
            if( i > 0 )
            {
                k = k/i;
                res += k +":";
            }
            else
                res += "Sin datos:";

            i = 0;
            k = 0;
            for( ; i < a7.size(); i++ )
            {
                k += a7.get(i).getValor();
            }
            if( i > 0 )
            {
                k = k/i;
                res += k +":";
            }
            else
                res += "Sin datos";

            return res;


        } catch (Exception ex) {
            Logger.getLogger(Oraculo.class.getName()).log(Level.SEVERE, null, ex);
            return "Sin datos:Sin datos:Sin datos:Sin datos:Sin datos:Sin datos:Sin datos";
        }
    }

    /**
     * Genera una alarma para un tipo de medida en una zona
     * @param tipoMedicion el tipo de medida a la que se le crea la alarma
     * @param latitud1 primera coordenada del primer punto
     * @param longitud1 segunda coordenada del primer punto
     * @param latitud2 primera coordenada del segundo punto
     * @param longitud2 segunda coordenada del segundo punto
     */
    public void generarAlarma(int tipoMedicion, Coordenada latitud1, Coordenada longitud1, Coordenada latitud2, Coordenada longitud2) {
    }

    private int[] calculoPrediccion() {
        return new int[1];
    }

    private void encontrarElementoMaximo(double[] array) {
    }

    private void calcularSenoCoseno() {
    }

    public int[] getColumnasGuardar() {
        return new int[1];
    }

    public boolean evaluarNoDiagonal() {
        return true;
    }
}
